home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
vbccwossrc.lha
/
vbcc
/
pasm
/
support.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-07
|
7KB
|
291 lines
/* $VER: pasm support.c V1.2 (21.10.98)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v1.2 (21.10.98) phx
* strncmpnc() compares first n chars of two strings non-case-sensitive.
* v1.1d (27.09.98) phx
* fopen() uses binary mode "b" for windoze/msdog compatibility.
* v0.5 (12.10.97) phx
* lower_case(), converts a whole string to lower case.
* try_mapfile() adds a '\n'-byte to every file it reads.
* v0.4 (28.06.97) phx
* remnode(), removes a node from a list.
* mapfile() automatically adds '/' to an include path.
* v0.3 (26.03.97)
* Little to big endian conversion routine - l2bh(), l2bw().
* v0.2 (25.03.97) phx
* Writes ELF object for 32-bit PowerPC big-endian. Either absolute
* or ELF output format may be selected. ELF is default for all
* currently supported platforms. PPCasm supports nine different
* relocation types (there are much more...).
* Compiles and works also under NetBSD/amiga (68k).
* Changed function declaration to 'new style' in all sources
* (to avoid problems with '...' for example).
* checkrange() prints a warning message on overflow and no error.
* remhead() returns NULL when list is empty.
* v0.1 (11.03.97) phx
* First test version with all PowerPC instructions and most
* important directives. Only raw, absolute output.
* checkrange() size 3 checks for 26-bit values instead 24-bit.
* Do we need a special allocation routine for strings?
* v0.0 (15.02.97) phx
* File created.
*/
#define SUPPORT_C
#include "ppcasm.h"
void *alloc(size_t);
void *alloczero(size_t);
char *allocstring(char *);
void initlist(struct list *);
void addtail(struct list *,struct node *);
struct node *remhead(struct list *);
char *mapfile(struct GlobalVars *,char *);
void checkrange(uint32,int,bool);
#ifdef LITTLEENDIAN
uint16 l2bh(uint16);
uint32 l2bw(uint32);
#endif
static char *try_mapfile(char *);
static size_t filesize(FILE *,char *);
void *alloc(size_t size)
/* allocate memory and print error message if not enough available */
{
void *p;
if (!size)
size = 1;
if (!(p = malloc(size)))
error(1); /* out of memory */
return (p);
}
void *alloczero(size_t size)
/* same as alloc() but zeroes the allocated memory */
{
void *p = alloc(size);
memset(p,0,size);
return (p);
}
char *allocstring(char *s)
/* allocate space for a single string */
/* @@@ this should be improved by some kind of string buffer */
{
char *p = alloc(strlen(s)+1);
strcpy(p,s);
return (p);
}
void initlist(struct list *l)
/* initializes a list structure */
{
l->first = (struct node *)&l->dummy;
l->dummy = NULL;
l->last = (struct node *)&l->first;
}
void addtail(struct list *l,struct node *n)
/* add node as last element of list */
{
struct node *ln = l->last;
n->next = ln->next;
ln->next = n;
n->pred = ln;
l->last = n;
}
struct node *remhead(struct list *l)
/* remove first node in list and return a pointer to it */
{
struct node *n = l->first;
if (n->next) {
l->first = n->next;
n->next->pred = n->pred;
return (n);
}
return (NULL);
}
struct node *remnode(struct node *n)
/* remove a node from a list */
{
n->next->pred = n->pred;
n->pred->next = n->next;
return (n);
}
char *mapfile(struct GlobalVars *gv,char *name)
/* map a complete file into memory and return its address */
/* the file's length is returned in *(p-sizeof(size_t)) */
/* all defined paths will be searched for the file, before aborting */
{
char *p;
int i;
size_t l;
char full_name[FNAMEBUFSIZE];
if (p = try_mapfile(name))
return (p);
for (i=0; i<MAX_INCPATHS; i++) {
if (gv->incpaths[i]) {
strncpy(full_name,gv->incpaths[i],FNAMEBUFSIZE-1);
l = strlen(gv->incpaths[i]);
if (l < (FNAMEBUFSIZE-2)) {
if (full_name[l-1]!='/' && full_name[l-1]!=':')
full_name[l++] = '/';
strncat(full_name,name,(FNAMEBUFSIZE-1)-l);
if (p = try_mapfile(full_name))
return (p);
}
}
}
error(6,name); /* can't open file */
}
static char *try_mapfile(char *name)
{
FILE *fp;
char *p=NULL;
size_t fsiz;
if (fp = fopen(name,"rb")) {
fsiz = filesize(fp,name);
p = alloc(fsiz+1+sizeof(size_t));
*(size_t *)p = fsiz + 1; /* store file size before the text starts */
p += sizeof(size_t);
if (fread(p,1,fsiz,fp) != fsiz) {
fclose(fp);
error(5,name); /* read error */
}
fclose(fp);
*(p+fsiz) = '\n'; /* always have a '\n'-byte at the end */
}
return (p);
}
static size_t filesize(FILE *fp,char *name)
{
/* somebody knows a better way to determine file size in ANSI C? */
long oldpos,size;
if ((oldpos = ftell(fp)) >= 0)
if (fseek(fp,0,SEEK_END) >= 0)
if ((size = ftell(fp)) >= 0)
if (fseek(fp,oldpos,SEEK_SET) >= 0)
return ((size_t)size);
fclose(fp);
error(5,name); /* read error - doesn't return */
}
void checkrange(uint32 val,int size,bool sign)
/* checks if an integer value is in range, size=3 means 26-bit (B-instr.) */
{
int sval;
if (sign) {
sval = (int)val;
switch (size) {
case 1:
if (sval>0x7f || sval<-0x80)
error(30,8); /* immediate operand doesn't fit into 8 bits */
break;
case 2:
if (sval>0x7fff || sval<-0x8000)
error(30,16);
break;
case 3:
if (sval>0x1ffffff || sval<-0x2000000)
error(30,24);
break;
}
}
else {
switch (size) {
case 1:
if (val>0xff)
error(30,8);
break;
case 2:
if (val>0xffff)
error(30,16);
break;
case 3:
if (val>0x3ffffff)
error(30,24);
break;
}
}
}
void lower_case(char *s)
/* convert a whole string to lower case */
{
unsigned char c;
while (c = (unsigned char)*s)
*s++ = tolower((int)c);
}
int strncmpnc(char *s1,char *s2,int n)
/* compares two strings non-case-sensitive */
{
int c;
while (n--) {
if (c = toupper((unsigned char)*s1++) - toupper((unsigned char)*s2++))
return (c);
}
return (0);
}
#ifdef LITTLEENDIAN
uint16 l2bh(uint16 x)
/* little endian half word conversion */
{
return ECH(x);
}
uint32 l2bw(uint32 x)
/* little endian word conversion */
{
return ECW(x);
}
#endif